package UserInput;

import idp.MainController;
import java.util.logging.Level;
import Command.*;
import debuggen.Debug;
import net.java.games.input.*;
/**
 * JoystickSidewinder
 * @author Danny
 * Class for Joystick: Microsoft SideWinder Dual Strike
 * Component values + order
 * Component: x value: 0.7556207   	Slider - left, right
 * Component: y value: -0.02052784  Slider - up, down
 * Component: 0 value: 0.0			Button - A
 * Component: 1 value: 0.0			Button - B
 * Component: 2 value: 0.0			Button - C
 * Component: 3 value: 0.0			Button - D
 * Component: 4 value: 0.0			Button - X
 * Component: 5 value: 0.0			Button - Y
 * Component: 6 value: 0.0			Button - "L1"
 * Component: 7 value: 0.0			Button - "R1"
 * Component: 8 value: 0.0			Button - Arrow up (Shift)
 * Component: pov value: 0.0		POV - See PointOfView.java
 */
public class JoystickSideWinder extends Joystick {
	// Commands
	private Command[] arrCommands = new Command[12];
	// Name of joystick
	public final static String NAME = "SideWinder Dual Strike";
	/**
	 * JoystickSideWinder
	 * @param p_cJoystick
	 * @param p_mcController
	 */
	public JoystickSideWinder(Controller p_cJoystick, MainController p_mcController) {
		super(p_cJoystick, p_mcController);	
		
		/**
		 * Commands to array index reference
		 * The correct command is placed at the index number, which is the same 
		 * place as in controller.getComponents which return an array.
		 */
		arrCommands[0] = new Rudder(); 				// X Slider
		arrCommands[1] = new NoCommand();			// Y Slider
		arrCommands[2] = new KeelUp();				// A Button
		arrCommands[3] = new Sail();				// B Button
		arrCommands[4] = new Sail();				// C Button
		arrCommands[5] = new KeelDown();			// D Button
		arrCommands[6] = new EngineOut();			// X Button
		arrCommands[7] = new NoCommand();			// Y Button
		arrCommands[8] = new NoCommand();			// L1 Button
		arrCommands[9] = new NoCommand();			// R1 Button
		arrCommands[10] = new NoCommand();			// Arrow up, shift Button
		arrCommands[11] = new NoCommand();			// POV, Button
	}
	/**
	 * run
	 */
	@Override
	public void run() {
		// Just walk on :)
		while(true)
		{
			/**
			 * Poll data from controller 
			 */
			// Check if SideWinder is still valid!
			if(!getJoystick().poll())
			{
				// If SideWinder is not valid, just end this thread
				return;
			}
		
			// Get and process data from SideWinder
			checkData();
			
			try 
			{
				// Sleep for a few ms!
				Thread.sleep(200);
			}catch(Exception exc)
			{
				// Write info to debug log
				if(Debug.DEBUGGEN)
				{
					Debug.writeMessage("Problem with joystick thread: " + exc.getMessage(), Level.WARNING, exc);
				}
			}
		}
	}
	/**
	 * checkData
	 * Checks data from SideWinder and process it.
	 */
	private synchronized void checkData()
	{
		// Components with new values!
		Component[] tmpValues = getJoystick().getComponents();
		
		// The first thing we do, is checking if we have a emergency!
		checkEmergency(tmpValues);
		
		// Rudder - X value
		float flX = tmpValues[0].getPollData();
		// Check if offset is >= 0.2
		if(Math.abs(flX) >= 0.30f)
		{
			// Set correct value
			arrCommands[0].setValue(convertValueToDegree(flX));
			// Send copy to the main controller
			mController.processUserInput(arrCommands[0]);
		}
		
		// Loop through buttons!
		for(int i = 2; i < 10; i++)
		{
			// If button is pressed
			if(tmpValues[i].getPollData() == 1.0f)
			{
				// Update value
				updateValue(arrCommands[i], tmpValues[i].getName());
				// Execute command
				mController.processUserInput(arrCommands[i]);
			}
		}
		
		// POV value
		double dlPovValue = tmpValues[11].getPollData();
		// Process POV value
		processPOV(dlPovValue);
		
	}
	/**
	 * UpdateValue
	 * Update value in the command, if needed!
	 * @param p_cmdCommand
	 * @param p_strExtraParam
	 */
	private void updateValue(Command p_cmdCommand, String p_strExtraParam)
	{
		// Sail value
		if(p_cmdCommand instanceof Sail)
		{
			// Turn sail to left
			if(p_strExtraParam.equals("1")) // 1 is button B
				arrCommands[3].setValue(mController.getDataWrapper().getSailPosition() + 32);
			// Turn sail to right
			else
				arrCommands[4].setValue(mController.getDataWrapper().getSailPosition() - 32);
		}
	}
	/**
	 * checkEmergency
	 * Check if we have a emergency (situation)
	 * @param Component[] - Buttons on SideWinder
	 * @return true, if we have a emergency (situation)
	 */
	public synchronized boolean checkEmergency(Component[] p_cmpButtons)
	{
		// Emergency stop (Buttons: Shift + L1 + R1)
		if(p_cmpButtons[8].getPollData() == 1.0f && 
		   p_cmpButtons[9].getPollData() == 1.0f && 
		   p_cmpButtons[10].getPollData() == 1.0f)
		{
			// Send the command for a emergency stop!
			mController.processUserInput(new EmergencyStop());
			return true;
		} // Emergency situation (Buttons: X + Y + A)
		else if(p_cmpButtons[6].getPollData() == 1.0f &&
				p_cmpButtons[7].getPollData() == 1.0f && 
				p_cmpButtons[2].getPollData() == 1.0f)
		{
			mController.processUserInput(new EmergencySituation());
			return true;
		}else {
			// There is nothing wrong :)
			return false;
		}
	}
	/**
	 * processPOV
	 * @param p_dlValue - Value from POV button
	 */
	private  synchronized void processPOV(double p_dlValue)
	{
		// Processing needs to be added when we have a agreement which button, which command executes.
		if(p_dlValue == PointOfView.N)// North
			mController.processUserInput(new EngineForward());
		else if(p_dlValue == PointOfView.Z) // South
			mController.processUserInput(new EngineBackward());
	}
	/**
	 * convertValueToDegree
	 * Convert values from joystick axis x to degrees
	 * Only called with offset of 30 %
	 * @param p_flXValue - Position on axis from joystick
	 * @return int - Degrees 
	 */
	public static int convertValueToDegree(float p_flXValue)
	{
		// Range from 0 - 255, 128 is middle
		return (int)Math.abs(128 + (p_flXValue * 128));
	}
}
